/*!
    \file  usb_delay.c 
    \brief time delay driver
*/

/*
    Copyright (C) 2016 GigaDevice

    2016-10-19, V1.0.0, demo for GD32F4xx
*/

#include "usb_delay.h"
#include "usb_conf.h"
#include "sys.h"

#define TIM_MSEC_DELAY 0x01U
#define TIM_USEC_DELAY 0x02U

__IO uint32_t hwp_delay_num = 0U;
__IO uint32_t timer_prescaler = 11U;

static void hwp_time_set(uint8_t unit);
static void hwp_delay(uint32_t nTime, uint8_t unit);

/*!
    \brief      initializes delay unit using timer2
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usb_time_init(void)
{
    INTX_DISABLE();

    /* enable the TIM2 gloabal interrupt */
    nvic_irq_enable((uint8_t)TIMER4_IRQn, 1U, 0U);

    rcu_periph_clock_enable(RCU_TIMER4);

    INTX_ENABLE();
}

/*!
    \brief      delay in micro seconds
    \param[in]  usec: value of delay required in micro seconds
    \param[out] none
    \retval     none
*/
void usb_udelay(const uint32_t usec)
{
    hwp_delay(usec, TIM_USEC_DELAY);
}

/*!
    \brief      delay in milli seconds
    \param[in]  msec: value of delay required in milli seconds
    \param[out] none
    \retval     none
*/
void usb_mdelay(const uint32_t msec)
{
    hwp_delay(msec, TIM_MSEC_DELAY);
}

/*!
    \brief      delay routine based on TIM2
    \param[in]  nTime: delay Time 
    \param[in]  unit: delay Time unit = mili sec / micro sec
    \param[out] none
    \retval     none
*/
static void hwp_delay(uint32_t nTime, uint8_t unit)
{
    hwp_delay_num = nTime;
    hwp_time_set(unit);

    while (0U != hwp_delay_num)
    {
    }

    timer_disable(TIMER4);
}

/*!
    \brief      configures TIM2 for delay routine based on TIM2
    \param[in]  unit: msec /usec
    \param[out] none
    \retval     none
*/
static void hwp_time_set(uint8_t unit)
{
    timer_parameter_struct timer_base_structure;

    timer_disable(TIMER4);
    timer_interrupt_disable(TIMER4, TIMER_INT_UP);

    if (TIM_USEC_DELAY == unit)
    {
        timer_base_structure.period = 7U; //12*8=96clk 1us
    }
    else if (TIM_MSEC_DELAY == unit)
    {
        timer_base_structure.period = 7999U; //1000us
    }
    else
    {
        /* no operation */
    }

    timer_base_structure.prescaler = (uint16_t)timer_prescaler;

    timer_base_structure.clockdivision = 0U;
    timer_base_structure.counterdirection = TIMER_COUNTER_UP;

    timer_init(TIMER4, &timer_base_structure);

    timer_interrupt_flag_clear(TIMER4, TIMER_INT_UP);

    timer_auto_reload_shadow_enable(TIMER4);

    /* TIM IT enable */
    timer_interrupt_enable(TIMER4, TIMER_INT_UP);

    /* TIM2 enable counter */
    timer_enable(TIMER4);
}
